package lg.minecraft.plugin.library.item;

import lombok.Getter;
import lombok.Setter;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author langle__
 * @version 1.0
 */
@Getter
@Setter
public class ItemProperties implements Cloneable {

    @NotNull private Material material = Material.AIR;
    @NotNull private String name = "";
    @NotNull private List<String> lore = new ArrayList<>();
    @NotNull private List<EnchantedEntry> enchantments = new ArrayList<>();
    @NotNull private List<ItemFlag> itemFlags = new ArrayList<>();

    public ItemProperties() {}

    public void addLore(@NotNull String lore) {
        this.lore.add(lore);
    }

    public void delLore(@NotNull String lore) {
        this.lore.remove(lore);
    }

    public void delLore(int index) {
        this.lore.remove(index);
    }

    public void setItemStack(ItemStack item) {
        setMaterial(item.getType());
        ItemMeta meta = item.getItemMeta();
        if (meta != null) {
            setName(meta.getDisplayName());
            List<String> lore = meta.getLore();
            setLore(lore == null ? new ArrayList<>() : lore);
            meta.getEnchants().forEach(this::addEnchant);
            meta.getItemFlags().forEach(this::addItemFlag);
        }
    }

    public void addEnchant(@NotNull Enchantment enchantment, int level) {
        enchantments.add(new EnchantedEntry(enchantment, level));
    }

    public void addItemFlag(@NotNull ItemFlag itemFlag) {
        itemFlags.add(itemFlag);
    }

    public boolean validate(ItemStack item) {
        ItemProperties properties = new ItemProperties();
        properties.setItemStack(item);
        return validate(properties);
    }

    public boolean validate(ItemProperties properties) {
        return this.material == properties.material && Objects.equals(this.name, properties.name) && Objects.equals(this.lore, properties.lore);
    }

    public ItemStack toItemStack() {
        ItemStack stack = new ItemStack(material);
        ItemMeta meta = stack.getItemMeta();
        if (meta != null) {
            meta.setDisplayName(name);
            meta.setLore(lore);
            enchantments.forEach(entry -> meta.addEnchant(entry.getEnchantment(), entry.getLevel(), true));
            itemFlags.forEach(meta::addItemFlags);
            stack.setItemMeta(meta);
        }
        return stack;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof ItemProperties)) return false;
        ItemProperties that = (ItemProperties) o;
        return material == that.material && Objects.equals(name, that.name) && Objects.equals(lore, that.lore);
    }

    @Override
    public int hashCode() {
        return Objects.hash(material, name, lore);
    }

    @Override
    public ItemProperties clone() {
        try {
            return (ItemProperties) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    @Getter
    public static class EnchantedEntry {
        private final Enchantment enchantment;
        private final int level;

        public EnchantedEntry(Enchantment enchantment, int level) {
            this.enchantment = enchantment;
            this.level = level;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            EnchantedEntry entry = (EnchantedEntry) o;
            return Objects.equals(enchantment, entry.enchantment);
        }

        @Override
        public int hashCode() {
            return Objects.hashCode(enchantment);
        }
    }

}
